//@author A0102127Y

#include "stdafx.h"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace Twentyfifth;
using namespace std;

namespace ParserUnitTest {
	TEST_CLASS(ParserUnitTest) {
public:

	//Shauna's unit testing
	TEST_METHOD(Parser_addTaskParseTesting) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton -start 2pm 11/10/2014 -end 1500 11/10/2014");
		string result = newCmd->toString();
		string expected = BLANK_STRING;
		expected = expected + "Description: badminton\n";
		expected = expected + "Start: 14:00 11/10/2014\n";
		expected = expected + "End: 15:00 11/10/2014\n";
		expected = expected + "Venue: \n";

		Assert::AreEqual(expected, result);
	}

	//boundary testing for starting date and time and ending date and time
	//minimum value 0000hrs 1 january 2014 to 2359 31 december 2014
	TEST_METHOD(Parser_addTaskParseTestingBoundary) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton -start 0000 01/01/2014 -end 2359 31/12/2014");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton\n";
		expected = expected + "Start: 00:00 01/01/2014\n";
		expected = expected + "End: 23:59 31/12/2014\n";
		expected = expected + "Venue: \n";

		Assert::AreEqual(expected, result);
	}


	//multiple word description
	TEST_METHOD(Parser_addTaskParseTesting02) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 0000 01/01/2014 -end 2359 31/12/2014");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 00:00 01/01/2014\n";
		expected = expected + "End: 23:59 31/12/2014\n";
		expected = expected + "Venue: \n";

		Assert::AreEqual(expected, result);
	}

	//multiple word description
	//start time with different am and pm format
	TEST_METHOD(Parser_addTaskParseTesting03) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 8am 01/01/2014 -end 9a.m. 31/12/2014");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 08:00 01/01/2014\n";
		expected = expected + "End: 09:00 31/12/2014\n";
		expected = expected + "Venue: \n";

		Assert::AreEqual(expected, result);
	}

	//multiple word description
	//start time with different am and pm format
	//with venue option
	TEST_METHOD(Parser_addTaskParseTesting04) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 8pm 01/01/2014 -end 11p.m. 31/12/2014 -venue mpsh");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 20:00 01/01/2014\n";
		expected = expected + "End: 23:00 31/12/2014\n";
		expected = expected + "Venue: mpsh\n";

		Assert::AreEqual(expected, result);
	}

	//multiple word description
	//start time with different date format
	//with venue option
	TEST_METHOD(Parser_addTaskParseTesting05) {
		int day;
		int month;
		int year;
		struct tm newtime;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;

		newtime.tm_mday++;

		tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date2 = buffer;

		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 8pm today -end 11p.m. tmr -venue mpsh");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 20:00 " + date1 + "\n";
		expected = expected + "End: 23:00 " + date2 + "\n";
		expected = expected + "Venue: mpsh\n";

		Assert::AreEqual(expected, result);
	}

	//multiple word description
	//start time with different time and date format (days)
	//with venue option
	TEST_METHOD(Parser_addTaskParseTesting06) {
		int day;
		int month;
		int year;
		struct tm newtime;
		struct tm newtime2;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		err = _localtime64_s(&newtime2, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}


		//convert the day to proper date
		int dayOfWeek = 2;
		int currDayOfWeek = newtime.tm_wday;
		if (dayOfWeek < currDayOfWeek) {
			dayOfWeek += 7;
		}
		int diff = dayOfWeek - currDayOfWeek;
		newtime.tm_mday += diff;

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;

		//convert the day to proper date
		dayOfWeek = 3;
		currDayOfWeek = newtime2.tm_wday;
		if (dayOfWeek < currDayOfWeek) {
			dayOfWeek += 7;
		}
		diff = dayOfWeek - currDayOfWeek;
		newtime2.tm_mday += diff;

		tempTime = &newtime2;
		mktime(tempTime);
		newtime2 = *tempTime;

		int day2 = newtime2.tm_mday;
		int month2 = newtime2.tm_mon + 1;
		int year2 = newtime2.tm_year + 1900;

		sprintf_s(buffer, "%02i/%02i/%04i", day2, month2, year2);
		string date2 = buffer;

		int startInt = year * 1000 + month * 100 + day;
		int endInt = year2 * 1000 + month2 * 100 + day2;

		if (startInt > endInt) {
			date2 = date1;
		}
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 8 tue -end 11p.m. wednesday -venue mpsh one");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 08:00 " + date1 + "\n";
		expected = expected + "End: 23:00 " + date2 + "\n";
		expected = expected + "Venue: mpsh one\n";

		Assert::AreEqual(expected, result);
	}

	//multiple word description
	//start time with different time and date format (days)
	//time and date position can be swapped
	//multiple words venue optino
	TEST_METHOD(Parser_addTaskParseTesting07) {
		int day;
		int month;
		int year;
		struct tm newtime;
		struct tm newtime2;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		err = _localtime64_s(&newtime2, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}


		//convert the day to proper date
		int dayOfWeek = 5;
		int currDayOfWeek = newtime.tm_wday;
		if (dayOfWeek < currDayOfWeek) {
			dayOfWeek += 7;
		}
		int diff = dayOfWeek - currDayOfWeek;
		newtime.tm_mday += diff;

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;

		//convert the day to proper date
		dayOfWeek = 0;
		currDayOfWeek = newtime2.tm_wday;
		if (dayOfWeek < currDayOfWeek) {
			dayOfWeek += 7;
		}
		diff = dayOfWeek - currDayOfWeek;
		newtime2.tm_mday += diff;

		tempTime = &newtime2;
		mktime(tempTime);
		newtime2 = *tempTime;

		int day2 = newtime2.tm_mday;
		int month2 = newtime2.tm_mon + 1;
		int year2 = newtime2.tm_year + 1900;

		sprintf_s(buffer, "%02i/%02i/%04i", day2, month2, year2);
		string date2 = buffer;

		int startInt = year * 1000 + month * 100 + day;
		int endInt = year2 * 1000 + month2 * 100 + day2;

		if (startInt > endInt) {
			date2 = date1;
		}

		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add swimming with jane -start fri 8 -end sun 12 -venue mpsh one plus");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: swimming with jane\n";
		expected = expected + "Start: 08:00 " + date1 + "\n";
		expected = expected + "End: 12:00 " + date2 + "\n";
		expected = expected + "Venue: mpsh one plus\n";

		Assert::AreEqual(expected, result);
	}


	//multiple word description
	//start time with different time and date format (days, case insensitive)
	//time and date position can be swapped
	//multiple words venue optino
	TEST_METHOD(Parser_addTaskParseTesting08) {
		int day;
		int month;
		int year;
		struct tm newtime;
		struct tm newtime2;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		err = _localtime64_s(&newtime2, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}


		//convert the day to proper date
		int dayOfWeek = 5;
		int currDayOfWeek = newtime.tm_wday;
		if (dayOfWeek < currDayOfWeek) {
			dayOfWeek += 7;
		}
		int diff = dayOfWeek - currDayOfWeek;
		newtime.tm_mday += diff;

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;

		//convert the day to proper date
		dayOfWeek = 1;
		currDayOfWeek = newtime2.tm_wday;
		if (dayOfWeek < currDayOfWeek) {
			dayOfWeek += 7;
		}
		diff = dayOfWeek - currDayOfWeek;
		newtime2.tm_mday += diff;

		tempTime = &newtime2;
		mktime(tempTime);
		newtime2 = *tempTime;

		int day2 = newtime2.tm_mday;
		int month2 = newtime2.tm_mon + 1;
		int year2 = newtime2.tm_year + 1900;

		sprintf_s(buffer, "%02i/%02i/%04i", day2, month2, year2);
		string date2 = buffer;

		int startInt = year * 1000 + month * 100 + day;
		int endInt = year2 * 1000 + month2 * 100 + day2;

		if (startInt > endInt) {
			date2 = date1;
		}

		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add swimming alone -start FRIDAY 0000 -end MonDAY 1900 -venue hdb");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: swimming alone\n";
		expected = expected + "Start: 00:00 " + date1 + "\n";
		expected = expected + "End: 19:00 " + date2 + "\n";
		expected = expected + "Venue: hdb\n";

		Assert::AreEqual(expected, result);
	}

	TEST_METHOD(Parser_addTaskParseTesting09) {
		int day;
		int month;
		int year;
		struct tm newtime;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;

		newtime.tm_mday++;

		tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date2 = buffer;

		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 8pm -end tmr -venue mpsh");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 20:00 " + date1 + "\n";
		expected = expected + "End: 08:00 " + date2 + "\n";
		expected = expected + "Venue: mpsh\n";

		Assert::AreEqual(expected, result);
	}

	//if end date is not specified, it is considered in the same day as start date
	TEST_METHOD(Parser_addTaskParseTesting10) {
		int day;
		int month;
		int year;
		struct tm newtime;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;

		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 8pm today -end 9pm -venue mpsh");
		string result = newCmd->toString();
		string expected = BLANK_STRING;

		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 20:00 " + date1 + "\n";
		expected = expected + "End: 21:00 " + date1 + "\n";
		expected = expected + "Venue: mpsh\n";

		Assert::AreEqual(expected, result);
	}

	//if end date is not specified, it is considered in the same day as start date
	TEST_METHOD(Parser_addTaskParseTesting11) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 8pm 02/11/2014 -end 9pm -venue mpsh");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 20:00 02/11/2014\n";
		expected = expected + "End: 21:00 02/11/2014\n";
		expected = expected + "Venue: mpsh\n";

		Assert::AreEqual(expected, result);
	}

	//if end date and time is not specified, it's an hour event
	TEST_METHOD(Parser_addTaskParseTesting12) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 12pm 02/11/2014");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 12:00 02/11/2014\n";
		expected = expected + "End: 13:00 02/11/2014\n";
		expected = expected + "Venue: \n";

		Assert::AreEqual(expected, result);
	}

	TEST_METHOD(Parser_addTaskParseTesting13) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -start 31/12/2014");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: badminton with john\n";
		expected = expected + "Start: 08:00 31/12/2014\n";
		expected = expected + "End: 09:00 31/12/2014\n";
		expected = expected + "Venue: \n";

		Assert::AreEqual(expected, result);
	}

	//deadline add, same time and date format and flexibility
	TEST_METHOD(Parser_addTaskParseTesting14) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add badminton with john -deadline 31/12/2014");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: badminton with john\n";
		expected = expected + "Deadline: 08:00 31/12/2014\n";
		expected = expected + "Venue: \n";
		expected = expected + "State: [ ] \n";

		Assert::AreEqual(expected, result);
	}

	//multiple word description
	//start time with different date format
	//with venue option
	TEST_METHOD(Parser_addTaskParseTesting15) {
		int day;
		int month;
		int year;
		struct tm newtime;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;


		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add do hw -venue home -deadline 11pm");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: do hw\n";
		expected = expected + "Deadline: 23:00 " + date1 + "\n";
		expected = expected + "Venue: home\n";
		expected = expected + "State: [ ] \n";

		Assert::AreEqual(expected, result);
	}

	//multiple word description
	//start time with different date format
	//with venue option
	TEST_METHOD(Parser_addTaskParseTesting16) {
		int day;
		int month;
		int year;
		struct tm newtime;
		__time64_t long_time;
		errno_t err;
		// Get time as 64-bit integer.
		_time64(&long_time);
		// Convert to local time.
		err = _localtime64_s(&newtime, &long_time);
		if (err) {
			printf("Invalid argument to _localtime64_s.");
			exit(1);
		}
		newtime.tm_mday += 1;

		struct tm* tempTime = &newtime;
		mktime(tempTime);
		newtime = *tempTime;

		day = newtime.tm_mday;
		month = newtime.tm_mon + 1;
		year = newtime.tm_year + 1900;

		char buffer[500];
		sprintf_s(buffer, "%02i/%02i/%04i", day, month, year);
		string date1 = buffer;


		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add do hw -venue home -deadline tmr");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: do hw\n";
		expected = expected + "Deadline: 08:00 " + date1 + "\n";
		expected = expected + "Venue: home\n";
		expected = expected + "State: [ ] \n";

		Assert::AreEqual(expected, result);
	}


	//add floating task (anything in the description)
	TEST_METHOD(Parser_addTaskParseTesting17) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add clean my room");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: clean my room\n";
		expected = expected + "State: [ ] \n";

		Assert::AreEqual(expected, result);
	}

	//add floating task (anything in the description)
	TEST_METHOD(Parser_addTaskParseTesting18) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("add print 2 lecture notes and put inside folders, module cs2103");
		string result = newCmd->toString();

		string expected = BLANK_STRING;
		expected = expected + "Description: print 2 lecture notes and put inside folders, module cs2103\n";
		expected = expected + "State: [ ] \n";

		Assert::AreEqual(expected, result);
	}

	//delete testing
	TEST_METHOD(Parser_deleteTaskParseTesting) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("delete 1");

		string result = newCmd->toString();
		string expected = "Id: 1\n";
		expected = expected + "Description: \n";

		Assert::AreEqual(expected, result);
	}

	//testing boundary test cases, invalid id
	TEST_METHOD(Parser_deleteTaskParseTestingInvalid) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("delete -1");

		string result = newCmd->toString();
		string expected = "invalid TaskType";

		Assert::AreEqual(expected, result);
	}

	//testing boundary of the id, which is the largest number for id (2^31 -1)
	TEST_METHOD(Parser_deleteTaskParseTestingBoundary) {
		// TODO: Your test code here
		Parser parser;
		Cmd* newCmd;
		newCmd = parser.parse("delete 2147483647");

		string result = newCmd->toString();
		string expected = "Id: 2147483647\n";
		expected = expected + "Description: \n";

		Assert::AreEqual(expected, result);
	}
	};
}